// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SparseTermVector.cs" company="Arizona State University">
//   Copyright (C) 2011-2012 Sukru Tikves and Arizona State University
//   
//   Released under Microsoft Public License (Ms-PL)
//   See http://cipsdata.codeplex.com/license for up to date license 
//   informaiton.
// </copyright>
// <summary>
//   The sparse term vector.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Cips.DataMining
{
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// The sparse term vector.
    /// </summary>
    /// <typeparam name="T">
    /// Keyword type.
    /// </typeparam>
    public class SparseTermVector<T> : TermVector<T>
    {
        /// <summary>
        /// The terms index.
        /// </summary>
        readonly Dictionary<int, int> index = new Dictionary<int, int>();

        /// <summary>
        /// Initializes a new instance of the <see cref="SparseTermVector{T}"/> class.
        /// </summary>
        /// <param name="dictionary">
        /// The dictionary.
        /// </param>
        public SparseTermVector(TermDictionary<T> dictionary)
            : base(dictionary)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SparseTermVector&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="dictionary">The dictionary.</param>
        /// <param name="data">The data.</param>
        public SparseTermVector(TermDictionary<T> dictionary, IEnumerable<KeyValuePair<int, double>> data)
            : base(dictionary)
        {
            foreach (var pair in data)
                this[pair.Key] = pair.Value;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SparseTermVector{T}"/> class.
        /// </summary>
        /// <param name="dictionary">
        /// The dictionary.
        /// </param>
        /// <param name="index">
        /// The terms index.
        /// </param>
        /// <param name="data">
        /// The term data.
        /// </param>
        SparseTermVector(TermDictionary<T> dictionary, Dictionary<int, int> index, IEnumerable<double> data)
            : base(dictionary)
        {
            Data.AddRange(data);

            foreach (var i in index)
                this.index.Add(i.Key, i.Value);
        }

        /// <summary>
        /// Gets or sets the data value associated with the specified term.
        /// </summary>
        /// <param name="term">
        /// The term.
        /// </param>
        /// <returns>
        /// The <see cref="double"/> value.
        /// </returns>
        public override double this[T term]
        {
            get
            {
                return index.ContainsKey(Dictionary[term]) ? Data[index[Dictionary[term]]] : 0;
            }

            set
            {
                var key = Dictionary[term];

                if (index.ContainsKey(key))
                    Data[index[key]] = value;
                else
                {
                    index.Add(key, Data.Count);
                    Data.Add(value);
                }
            }
        }

        /// <summary>
        /// Gets or sets the data value associated with the specified term.
        /// </summary>
        /// <param name="term">
        /// The term.
        /// </param>
        /// <returns>
        /// The <see cref="double"/> value.
        /// </returns>
        public override double this[int term]
        {
            get
            {
                return index.ContainsKey(term) ? Data[index[term]] : 0;
            }

            set
            {
                if (index.ContainsKey(term))
                    Data[index[term]] = value;
                else
                {
                    index.Add(term, Data.Count);
                    Data.Add(value);
                }
            }
        }

        /// <summary>
        /// Normalizes this instance.
        /// </summary>
        /// <returns>A normalized copy of this vector.</returns>
        public override TermVector<T> Normalize()
        {
            var sum = Data.Sum();

            return new SparseTermVector<T>(Dictionary, index, Data.Select(d => d / sum));
        }

        /// <summary>
        /// Gets the enumerator.
        /// </summary>
        /// <returns>An enumerator for term/value pairs.</returns>
        public override IEnumerator<KeyValuePair<int, double>> GetEnumerator()
        {
            return index.Select(i => new KeyValuePair<int, double>(i.Key, Data[i.Value])).GetEnumerator();
        }
    }
}